package database

import (
	"context"
	"dustbe/util"
	"errors"
	"fmt"
	"strings"

	"github.com/neo4j/neo4j-go-driver/v5/neo4j"
)

func FindStaffPublisherByStaffId(staffId int) (DustUser, error) {
	var dustUser DustUser
	exist := false

	m1 := "match (user:DustUser)"
	c1 := fmt.Sprintf("match (staff:Staff) where id(staff)=%d", staffId)
	c2 := "match (user)-[rb:Publish]->(staff)"
	r := "return user"

	cypher := m1 + " " + c1 + " " + c2 + " " + r

	session := Neo4jDriver.NewSession(neo4j.SessionConfig{
		AccessMode: neo4j.AccessModeRead,
	})
	defer session.Close(context.TODO())

	result, err := session.Run(context.TODO(), cypher, nil)
	if err != nil {
		return dustUser, err
	}

	for (result.Next(context.TODO())) {
		n, _ := result.Record().Get("user")
		node := n.(neo4j.Node)
		dustUser.Id = node.Id
		dustUser.ImgUrl = node.Props["imgUrl"].(string)
		dustUser.Name = node.Props["name"].(string)
		dustUser.HashedPassword = node.Props["hashedPassword"].(string)
		exist = true
	}

	if exist {
		return dustUser, nil
	} else {
		return dustUser, errors.New("用户不存在")
	}
}

func GetStaffNumber() (int, error) {
	var staffNum int
	cypher := "match (n:Staff) return count(n)"

	session := Neo4jDriver.NewSession(neo4j.SessionConfig{
		AccessMode: neo4j.AccessModeRead,
	})
	defer session.Close(context.TODO())

	result, err := session.Run(context.TODO(), cypher, nil)
	if err != nil {
		fmt.Println(err.Error())
		return staffNum, err
	}

	for result.Next(context.TODO()) {
		n, _ := result.Record().Get("count(n)")
		staffNum = int(n.(int64))
	}

	return staffNum, nil
}


func PublishStaff(publisherId, createTime int, title, imgUrl, publisherName string) (int64, error) {
	var staffId int64
	title = strings.TrimSpace(title)
	if len(title) == 0 {
		return staffId, errors.New("标题不能为空！")
	}

	m1 := fmt.Sprintf("match (user:DustUser) where id(user)=%d", publisherId)
	title, _ = util.AddDoubleQuote(title)
	imgUrl, _ = util.AddDoubleQuote(imgUrl)
	publisherName, _ = util.AddDoubleQuote(publisherName)
	c1 := fmt.Sprintf("create (staff:Staff{title:%s,imgUrl:%s,publisherName:%s,createTime:%d})", title, imgUrl, publisherName, createTime)
	c2 := "create (user)-[rb:Publish]->(staff)"
	r := "return staff"

	cypher := m1 + " " + c1 + " " + c2 + " " + r

	session := Neo4jDriver.NewSession(neo4j.SessionConfig{
		AccessMode: neo4j.AccessModeWrite,
	})
	defer session.Close(context.TODO())

	result, err := session.Run(context.TODO(), cypher, nil)
	if err != nil {
		return staffId, err
	}

	for (result.Next(context.TODO())) {
		n, _ := result.Record().Get("staff")
		staff := n.(neo4j.Node)
		staffId = staff.Id
	}

	return staffId, nil
}


func DeleteStaff(staffId int64) error {
	cypher := fmt.Sprintf("match (n:Staff) where id(n)=%d detach delete n", staffId)
	session := Neo4jDriver.NewSession(neo4j.SessionConfig{
		AccessMode: neo4j.AccessModeWrite,
	})
	defer session.Close(context.TODO())

	_, err := session.Run(context.TODO(), cypher, nil)
	return err
}


func ModifyStaff(staffId int64, title, imgUrl string) error {
	title, _ = util.AddDoubleQuote(title)
	imgUrl, _ = util.AddDoubleQuote(imgUrl)
	cypher := fmt.Sprintf("match (n:Staff) where id(n)=%d set n.title=%s set n.imgUrl=%s", staffId, title, imgUrl)

	session := Neo4jDriver.NewSession(neo4j.SessionConfig{
		AccessMode: neo4j.AccessModeWrite,
	})
	defer session.Close(context.TODO())

	_, err := session.Run(context.TODO(), cypher, nil)

	return err
}

type StaffNode struct {
	Id int64 `json:"id"`
	PublisherName string `json:"publisherName"`
	ImgUrl string `json:"imgUrl"`
	Title string `json:"title"`
	CreateTime int64 `json:"createTime"`
}

// pageId 从 1 开始
func GetStaffByPage(pageId, staffNumOnePage int) ([]StaffNode, error) {
	staffNodes := make([]StaffNode, 0)

	skipPages := (pageId - 1) * staffNumOnePage
	cypher := fmt.Sprintf("match (n:Staff) return n order by n.createTime desc skip %d limit %d", skipPages, staffNumOnePage)
	session := Neo4jDriver.NewSession(neo4j.SessionConfig{
		AccessMode: neo4j.AccessModeRead,
	})
	defer session.Close(context.TODO())

	result, err := session.Run(context.TODO(), cypher, nil)
	if err != nil {
		fmt.Println(err.Error())
		return staffNodes, err
	}
	
	for (result.Next(context.TODO())) {
		n, _ := result.Record().Get("n")
		node := n.(neo4j.Node)
		staffNode := StaffNode{
			Id: node.Id,
			PublisherName: node.Props["publisherName"].(string),
			ImgUrl: node.Props["imgUrl"].(string),
			Title: node.Props["title"].(string),
			CreateTime: node.Props["createTime"].(int64),
		}
		staffNodes = append(staffNodes, staffNode)
	}
	return staffNodes, nil
}

func GetStaffById(staffId int64) (StaffNode, error) {
	var staffNode StaffNode
	
	cypher := fmt.Sprintf("match (n:Staff) where id(n)=%d return n", staffId)
	session := Neo4jDriver.NewSession(neo4j.SessionConfig{
		AccessMode: neo4j.AccessModeRead,
	})
	defer session.Close(context.TODO())

	result, err := session.Run(context.TODO(), cypher, nil)
	if err != nil {
		return staffNode, err
	}

	for (result.Next(context.TODO())) {
		n, _ := result.Record().Get("n")
		node := n.(neo4j.Node)
		staffNode = StaffNode{
			Id: node.Id,
			PublisherName: node.Props["publisherName"].(string),
			ImgUrl: node.Props["imgUrl"].(string),
			Title: node.Props["title"].(string),
			CreateTime: node.Props["createTime"].(int64),
		}
	}
	
	return staffNode, nil
}